#! /usr/bin/env python
import logging
from optparse import OptionParser
import os
import sys
import time
import urllib2
import urlparse
import xml.dom.minidom

global debug; debug = True    # or '' but not False
global fixme; fixme = True
global server; server= 'http://www.wowarmory.com'
global logpath; logpath = '/home/derek/wow/logs'

class whoshe:
    def __init__(self, data = []):
        if not os.path.exists(logpath):
            print 'You must create filepath %s before logging can take place.' % logpath
            print 'Alternatively, you may choose a path of your own and edit this script file,'
            print sys.argv[0]
            sys.exit()
        options, args = dispatch.parser.parse_args()
        if not args:
            if fixme: print 'fixme:update all characters (future intent)\n'
            print 'If you intended to get help running this script,'
            print 'Try \'%s -h\'' % sys.argv[0]
            sys.exit()
        characterlist = self.processargs(args)
        i = 0
        localstart = time.time()

        # fetch character sheets
        print 'Fetching data from server.'
        for realm, name in characterlist:
            test = self.fetch(realm, name, 'character', options.debug)
            try:
                classid = int(test.getElementsByTagName('character')[0].getAttribute('classId'))
                data.append(test)
                if False and classid == 4:
                    pass # get rogue stats, if desired -- needs to be written
            except IndexError:
                print 'Character sheet %s / %s dumped -- reason:' % (realm, name), test.getElementsByTagName('characterInfo')[0].getAttribute('errCode')
        if len(characterlist) > 1:
            print '\nTotal time to fetch characters: %.2f s' % (time.time() - localstart)

        # process character sheets
        commalist = tablist = []

        # report character data to logs
        if options.talents:     # pass only talents, health, mana, and healing stats; log normally
            headform ='\n%7s  %-20s  %-12s  %6s  %6s  %4s'
            logform = '%7s  %-20s  %2d / %2d / %2d  %6s  %6s  %4d'
            print headform % ('Class', 'Name', 'Talents', 'Health', 'Mana', 'Heal')
            for sheet in data:
                z = armory(sheet)
                print logform % (z.classs, z.name, z.talents[0], z.talents[1], z.talents[2], z.health, z.mana, z.heal)
                x = self.loggit(z, 'csv')
                if x: self.loggit(z, 'txt')

        else:               # pass normal data through, and send it to logs
            commalist = []
            tablist = []
            for sheet in data:
                z = armory(sheet)
                self.console(z)
                comma = self.loggit(z, 'csv')   # comma delimited
                if comma:
                    commalist.append(comma)
                    tab = self.loggit(z, 'txt')     # tab delimited
                    tablist.append(tab)
            if commalist:
                print '\n\t%s\n\nComma-delimited log files updated:' % ('/'*50)
                for log in commalist: print log
                print '\nTab-delimited log files updated:'
                for log in tablist: print log
            else:
                print 'No updates to any of the logs.'
        print '\nTotal time from the first download: %.2f s\n' % (time.time() - localstart)

    def processargs(self, arguments, characterlist = [], x = '/', realm = ''):
        for arg in arguments:
            try:
                arg.index(x)
                realm, x, name = arg.partition(x)
                realm = realm.replace('+', ' ').title()
                name = name.title()
            except ValueError:
                if realm: name = arg.title()    # if there is no '/', use the realm from the last hit
                else:
                    print 'Try \'%s -h\'' % sys.argv[0]
                    sys.exit()
            characterlist.append((realm, name))  # realm, name tuples
        return set(characterlist)

    def console(self, sheet):
        print '\n\t%s\n' % (50*'=')
        print '%d %s of %s (%s) - %s %s\n' % (sheet.level, sheet.name, sheet.realm, sheet.battlegroup, sheet.faction, sheet.classs)
        age = (time.time() - sheet.date)/(24.*60*60)
        print 'Update: %s  (%.1f days)   -   %s' % (sheet.logdate, age, sheet.guild)
        if not len(sheet.titles): sheet.titles = [None]
        print 'Known titles: %s' % sheet.titles.pop()
        if len(sheet.titles) == 1:
            print '%s%s' % (' '*14, sheet.titles.pop())
        elif len(sheet.titles) > 1:
            for i in len(sheet.titles):
                print '%s%s' % (' '*14, sheet.titles.pop())

        print '\nTalents:  %2d / %2d / %2d' % sheet.talents
        print '%s health,  %s mana,  %s mp5\n' % (sheet.health, sheet.mana, sheet.mp5)

        if sheet.melee:
            x = sheet.melee
            print 'MH %.1f dps, %.2f speed' % (x['mainhand'][0], x['mainhand'][1])
            if x['offhand'][0]:
                print 'OH %.1f dps, %.2f speed' % (x['offhand'][0], x['offhand'][1])
            print 'AP: %.1f dps, crit: %.2f, hit: %.2f, expertise: %.2f\n' % (x['power'][0], x['crit'][0], x['hit'][0], x['expert'][0])

        if sheet.ranged:
            x = sheet.ranged
            print 'Range %.1f dps, %.2f speed -' % (x['damage'][0], x['damage'][1]),
            print 'RAP: %.1f dps, crit: %.2f, hit: %.2f\n' % (x['power'][0], x['crit'][0], x['hit'][0])

        if sheet.spell:
            x = sheet.spell
            for school, value in x.iteritems():
                print '%6s  %4d,  %5.2f %% crit' % (school, value[0], value[1])
            print 'healing %4d,  penetration  %d\n' % (sheet.heal, sheet.pen)

        if sheet.defenses:
            x = sheet.defenses
            print 'armor: %.2f %% -' % x['armor'][0],
            print 'resilience: -%.2f %% damage, -%.2f %% hit' % (x['resilience'][0], x['resilience'][1])
            print 'dodge/parry: %.2f %%; block %.2f %% - crush avoidance: %.2f %%\n' % (x['pd'], x['block'][0], x['pdb'])

        print '%s honorable kills, %d arena currency' % (sheet.kills, sheet.arenacurr)
        if sheet.arena:
            for size, data in sheet.arena.iteritems():
                print '%d - %-23s rank %5s,  rate %4d,  contrib %4d,  teamrank %d' % (size, data[0][:23], data[1], data[2], data[3], data[4])

    def loggit(self, sheet, format):
        logfile = '%s.%s' % (urlparse.urljoin(logpath + '/', sheet.logfile), format)
        loghead, logdata = self.logforms(format, sheet)

        # set up logging to file
        try:
            log = open(logfile, 'r')
            log.close()
            logdate = os.stat(logfile).st_mtime
            if logdate == sheet.date:    # no update
                logstate = False
                print 'No update for %s/%s. Therefore, no log update.' % (sheet.realm, sheet.name)
                return ''
            else:                       # update is found
                logstate = 'append'
        except IOError:
            logstate = 'fresh'
            try: os.mkdir(os.path.split(logfile)[0])
            except OSError: pass
            initlog = open(logfile, 'w')
            header = '%s of %s - %s %s\n' % (sheet.name, sheet.realm, sheet.faction, sheet.classs)
            initlog.write(header)
            initlog.write(loghead)
            initlog.close()

        # return to normal logging
        log = open(logfile, 'a')
        log.write(logdata + '\n')
        log.close()

        #set date to sheet.logdate
        accesstime = os.stat(logfile).st_atime      # just because i have to have a retarded tuple
        os.utime(logfile, (accesstime, sheet.date))
        return logfile

    def logforms(self, format, sheet):
        x = sheet.classid
        if format == 'csv':
            classheader = {
                1: 'MHdps, OHdps, Crit, Parry and dodge, Block, Total, Armor',
                2: 'Mana, MP5, Spell damage, Heal, Spell crit, MHdps, OHdps, Melee crit, Parry and dodge, Block, Total, Armor',
                3: 'DPS, crit',
                4: 'MHdps, OHdps, Crit',
                5: 'Mana, MP5, Spell damage, Heal, Spell crit',
                # 6 is not used
                7: 'Mana, MP5, Spell damage, Heal, Spell crit, MHdps, OHdps, Crit',
                8: 'Mana, MP5, Spell damage, Spell crit',
                9: 'Mana, MP5, Spell damage, Spell crit',
                #10 is not used
                11:'Mana, MP5, Spell damage, Heal, Spell crit, APdps, Melee crit, Dodge, Armor',
            }
            header = \
                'Date, Level, Talent1, Talent2, Talent3, Health, ' + \
                '%s, ' % classheader[sheet.classid] + \
                'Profession, Skill, Profession, Skill\n'
            # set up log format selon class
            if x == 1:      # warrior
                logformat = \
                    '%.1f, %.1f, %.2f, ' % (sheet.melee['mainhand'][0], sheet.melee['offhand'][0], sheet.melee['crit'][0]) + \
                    '%.2f, %.2f, %.2f, %.2f' % (sheet.defenses['pd'], sheet.defenses['block'][0], sheet.defenses['pdb'], sheet.defenses['armor'][0])
            elif x == 2:    # paladin
                logformat = \
                    '%s, %d, %d, %d, %.2f, ' % (sheet.mana, sheet.mp5, sheet.spell['holy'][0], sheet.heal, sheet.spell['holy'][1]) + \
                    '%.1f, %.1f, %.2f, ' % (sheet.melee['mainhand'][0], sheet.melee['offhand'][0], sheet.melee['crit'][0]) + \
                    '%.2f, %.2f, %.2f, %.2f' % (sheet.defenses['pd'], sheet.defenses['block'][0], sheet.defenses['pdb'], sheet.defenses['armor'][0])
            elif x == 3:    # hunter
                logformat = '%.1f, %.2f' % (sheet.ranged['damage'][0], sheet.ranged['crit'][0])
            elif x == 4:    # rogue
                logformat = '%.1f, %.1f, %.2f' % (sheet.melee['mainhand'][0], sheet.melee['offhand'][0], sheet.melee['crit'][0])
            elif x == 5:    # priest
                logformat = '%s, %d, %d, %d, %.2f' % (sheet.mana, sheet.mp5, sheet.spell['shadow'][0], sheet.heal, sheet.spell['holy'][1])
            elif x == 7:    # shaman
                logformat = \
                    '%s, %d, %d, %d, %.2f, ' % (sheet.mana, sheet.mp5, sheet.spell['nature'][0], sheet.heal, sheet.spell['nature'][1]) + \
                    '%.1f, %.1f, %.2f' % (sheet.melee['mainhand'][0], sheet.melee['offhand'][0], sheet.melee['crit'][0])
            elif x == 8:    # mage
                logformat = '%s, %d, %d, %.2f' % (sheet.mana, sheet.mp5, sheet.spell['arcane'][0], sheet.spell['arcane'][1])
            elif x == 9:    # warlock
                logformat = '%s, %d, %d, %.2f' % (sheet.mana, sheet.mp5, sheet.spell['shadow'][0], sheet.spell['shadow'][1])
            elif x == 11:   # druid
                logformat = \
                    '%s, %d, %d, %d, %.2f, ' % (sheet.mana, sheet.mp5, sheet.spell['nature'][0], sheet.heal, sheet.spell['nature'][1]) + \
                    '%.1f, %.2f, ' % (sheet.melee['power'][0], sheet.melee['crit'][0]) + \
                    '%.2f, %.2f' % (sheet.defenses['dodge'][0], sheet.defenses['armor'][0])
            else:
                print 'fixme: No comma log format is set for this character\'s class. (%s, %d)' % (sheet.classs, sheet.classid)
            # end set up selon class
            logdata = '%s, %d, %d, %d, %d, %s, ' % (sheet.logdate, sheet.level, sheet.talents[0], sheet.talents[1], sheet.talents[2], sheet.health) + logformat
            for prof in sheet.professions:
                logdata = logdata + ', %s, %d' % (prof, sheet.professions[prof])

        elif format == 'txt':
            classheader = {
                1:  '%5s  %5s  %5s  ' % ('MHdps', 'OHdps', 'MCrit') + \
                    '%5s  %5s  %5s  %5s' % ('p+d', 'Block', 'Total', 'Armor'),
                2:  '%6s  %3s  %4s  %4s  %5s  ' % ('Mana', 'MP5', 'Spll', 'Heal', 'SCrit') + \
                    '%5s  %5s  %5s  ' % ('MHdps', 'OHdps', 'MCrit') + \
                    '%5s  %5s  %5s  %5s' % ('p+d', 'Block', 'Total', 'Armor'),
                3:  '%5s  %5s' % ('DPS', 'crit'),
                4:  '%5s  %5s  %5s' % ('MHdps', 'OHdps', 'Crit'),
                5:  '%6s  %3s  %4s  %4s  %5s' % ('Mana', 'MP5', 'Spll', 'Heal', 'SCrit'),
                # 6 is not used
                7:  '%6s  %3s  %4s  %4s  %5s  ' % ('Mana', 'MP5', 'Spll', 'Heal', 'SCrit') + \
                    '%5s  %5s  %5s' % ('MHdps', 'OHdps', 'MCrit'),
                8:  '%6s  %3s  %4s  %5s' % ('Mana', 'MP5', 'Spll', 'SCrit'),
                9:  '%6s  %3s  %4s  %5s' % ('Mana', 'MP5', 'Spll', 'SCrit'),
                #10 is not used
                11: '%6s  %3s  %4s  %4s  %5s  ' % ('Mana', 'MP5', 'Spll', 'Heal', 'SCrit') + \
                    '%5s  %5s  %5s  %5s' % ('APdps', 'MCrit', 'Dodge', 'Armor'),
                }

            header = \
                '%8s  %2s  %8s  %6s  ' % ('Modified', 'Lv', 'Talents', 'Health') + \
                '%s' % classheader[sheet.classid] + \
                '  %14s  %3s  %14s  %3s\n' % ('Profession', '#', 'Profession', '#')

            if x == 1:      # warrior
                logformat = \
                    '%5.1f  %5.1f  %5.2f  ' % (sheet.melee['mainhand'][0], sheet.melee['offhand'][0], sheet.melee['crit'][0]) + \
                    '%5.2f  %5.2f  %5.2f  %5.2f' % (sheet.defenses['pd'], sheet.defenses['block'][0], sheet.defenses['pdb'], sheet.defenses['armor'][0])
            elif x == 2:    # paladin
                logformat = \
                    '%6s  %3d  %4d  %4d  %5.2f  ' % (sheet.mana, sheet.mp5, sheet.spell['holy'][0], sheet.heal, sheet.spell['holy'][1]) + \
                    '%5.1f  %5.1f  %5.2f  ' % (sheet.melee['mainhand'][0], sheet.melee['offhand'][0], sheet.melee['crit'][0]) + \
                    '%5.2f  %5.2f  %5.2f  %5.2f' % (sheet.defenses['pd'], sheet.defenses['block'][0], sheet.defenses['pdb'], sheet.defenses['armor'][0])
            elif x == 3:    # hunter
                logformat = '%5.1f  %5.2f' % (sheet.ranged['damage'][0], sheet.ranged['crit'][0])
            elif x == 4:    # rogue
                logformat = '%5.1f  %5.1f  %5.2f' % (sheet.melee['mainhand'][0], sheet.melee['offhand'][0], sheet.melee['crit'][0])
            elif x == 5:    # priest
                logformat = '%6s  %3d  %4d  %4d  %5.2f' % (sheet.mana, sheet.mp5, sheet.spell['shadow'][0], sheet.heal, sheet.spell['holy'][1])
            elif x == 7:    # shaman
                logformat = \
                    '%6s  %3d  %4d  %4d  %5.2f  ' % (sheet.mana, sheet.mp5, sheet.spell['nature'][0], sheet.heal, sheet.spell['nature'][1]) + \
                    '%5.1f  %5.1f  %5.2f' % (sheet.melee['mainhand'][0], sheet.melee['offhand'][0], sheet.melee['crit'][0])
            elif x == 8:    # mage
                logformat = '%6s  %3d  %4d  %5.2f' % (sheet.mana, sheet.mp5, sheet.spell['arcane'][0], sheet.spell['arcane'][1])
            elif x == 9:    # warlock
                logformat = '%6s  %3d  %4d  %5.2f' % (sheet.mana, sheet.mp5, sheet.spell['shadow'][0], sheet.spell['shadow'][1])
            elif x == 11:   # druid
                logformat = \
                    '%6s  %3d  %4d  %4d  %5.2f  ' % (sheet.mana, sheet.mp5, sheet.spell['nature'][0], sheet.heal, sheet.spell['nature'][1]) + \
                    '%5.1d  %5.2f  ' % (sheet.melee['power'][0], sheet.melee['crit'][0]) + \
                    '%5.2f  %5.2f' % (sheet.defenses['dodge'][0], sheet.defenses['armor'][0])
            else:
                print 'fixme: No tab-delimited log format is set for this character\'s class. (%s, %d)' % (sheet.classs, sheet.classid)
            # end set up selon class

            logdata =   '%8s  %2d  %2d/%2d/%2d  %6s  ' % (sheet.logdate, sheet.level, sheet.talents[0], sheet.talents[1], sheet.talents[2], sheet.health) + logformat
            for prof in sheet.professions:
                logdata = logdata+ '  %14s  %3d' % (prof, sheet.professions[prof])

        else: print 'No formatting instructions to print to %s format.' % format
        return header, logdata

    def general(self, sheet):
        pass    # don't know what to write for this
        return None

    def fetch(self, realm, name, sheet, debug = False):
        if debug:
            localstart = time.time()
            logform = '\t%5.2f s %s'
            print '\n%s / %s:' % (realm, name)
        sheeturl = {
            'character':    'character-sheet.xml',
            'reputation':   'character-reputation.xml',
            'skills':       'character-skills.xml',
            'talents':      'character-talents.xml',
            #'arenateams':   'character-arenateams.xml',    # not needed; the data is on every other sheet
            }
        url = '%s?r=%s&n=%s' % (urlparse.urljoin(server + '/', sheeturl[sheet]), realm, name)
        oOpener = urllib2.build_opener()
        oOpener.addheaders = [('user-agent', 'Firefox/2.0 - whoshe.py 0.9 alpha'),]
        if debug: print '\tContacting %s...' % server
        req = urllib2.Request(url)
        if debug: print logform % (time.time() - localstart, 'to request')
        xmlfile = oOpener.open(req)
        if debug: print logform % (time.time() - localstart, 'to open')
        xmldata = xml.dom.minidom.parse(xmlfile)
        if debug: print logform % (time.time() - localstart, 'to parse')
        return xmldata

class dispatch:     # for help, http://docs.python.org/lib/module-optparse.html
    usage = 'usage: %prog [options] realm/name [realm/]name ...'
    parser = OptionParser(usage=usage)
    parser.add_option("-t",
        action="store_true", dest="talents",
        help="print talents, health, mana, and healing only")
    parser.add_option('-d',
        action='store_true', dest='debug',
        help='activate debug logging (console output only) -- data such as time it takes to download each character sheet')

class armory:
    def __init__(self, sheet, demo = False):
        '''
        NAMESPACE VARIABLES (where a * follows, it is a dictionary)
        battlegroup                     talents (tuple) heal
        classs (note the extra s)       buffs*          pen(etration)
        faction                         kills           defenses*
        gender                          arenacurr       item* (by slot index)
        guild                           professions*    slot* (by name)(conjectural)
        level                           titles (list)
        name                            health
        race                            mana
        realm                           mp5
        date (float)                    base*
        logdate (yyyy-ddd)              resist*
        titlename                       melee*
        logfile                         ranged*
        arena* (the teams)              spell*

        classes[] is mostly just for human reference,
        but allows the programmer to use classes['warrior'] in the place of
        the integer 1 when it is not readily known what id goes with the class.
        Example:
        schools[classes['paladin']] == schools[2] == ['holy']
        '''

        #basic initialization
        classes = {
            'warrior':  1,
            'paladin':  2,
            'hunter':   3,
            'rogue':    4,
            'priest':   5,
            # 6 is not used atm
            'shaman':   7,
            'mage':     8,
            'warlock':  9,
            # 10 is not used atm
            'druid':    11,
            }
        combats = {
            1: ['melee',                            'defenses'],
            2: ['melee',           'spell', 'heal', 'defenses'],
            3: [         'ranged',                            ],
            4: ['melee',                                      ],
            5: [                   'spell', 'heal',           ],
            # 6 is not used
            7: ['melee',           'spell', 'heal',           ],
            8: [                   'spell',                   ],
            9: [                   'spell',                   ],
            #10 is not used
            11:['melee',           'spell', 'heal', 'defenses'],
            }
        schools = {
            1: [                                                     ], # for the sake of completeness
            2: [                           'holy',                   ],
            3: [                                                     ], # for the sake of completeness
            4: [                                                     ], # for the sake of completeness
            5: [                           'holy',           'shadow'],
            # 6 is not used
            7: [          'fire', 'frost',         'nature',         ],
            8: ['arcane', 'fire', 'frost',                           ],
            9: [          'fire',                            'shadow'],
            #10 is not used
            11:['arcane',                          'nature',         ],
            }
        stats = {
            1: ['strength', 'agility', 'stamina',                      ],
            2: [                       'stamina', 'intellect',         ],
            3: [            'agility', 'stamina', 'intellect',         ],
            4: [            'agility', 'stamina',                      ],
            5: [                       'stamina', 'intellect', 'spirit'],
            # 6 is not used
            7: ['strength',            'stamina', 'intellect',         ],
            8: [                       'stamina', 'intellect',         ],
            9: [                       'stamina', 'intellect',         ],
            #10 is not used
            11:['strength', 'agility', 'stamina', 'intellect', 'spirit'],
            }

        #raw data
        general = sheet.getElementsByTagName('character')[0]
        self.battlegroup = general.getAttribute('battleGroup')
        self.classs = general.getAttribute('class')
        self.classid = int(general.getAttribute('classId'))
        self.faction = general.getAttribute('faction')   # also factionId
        self.gender = general.getAttribute('gender') # also genderId
        guild = general.getAttribute('guildName')   # also guildUrl
        lastmodified = general.getAttribute('lastModified')
        self.level = int(general.getAttribute('level'))
        self.name = general.getAttribute('name')
        prefix = general.getAttribute('prefix')
        self.race = general.getAttribute('race') # also raceId
        self.realm = general.getAttribute('realm')
        suffix = general.getAttribute('suffix')

        #derivatives
        update = time.strptime(lastmodified, '%B %d, %Y')
        self.date = time.mktime(update)                  # float
        self.logdate = time.strftime('%Y-%j', update)    # yyyy-ddd (day of the year)
        self.guild = guild and '<' + guild + '>' or '/guildless/'
        self.titlename = prefix + self.name + suffix
        self.logfile = urlparse.urljoin(self.realm + '/', self.name)

        self.arena = {}
        try:
            arena = general.getElementsByTagName('arenaTeams')[0].getElementsByTagName('arenaTeam')
        except IndexError: arena = None
        if arena:
            for team in arena:
                size = int(team.getAttribute('size'))
                name = team.getAttribute('name')
                ranking = int(team.getAttribute('ranking'))
                if ranking < 1000: rank = ranking
                else: rank = '%2d %03d' % divmod(ranking, 1000)
                rating = int(team.getAttribute('rating'))
                members = team.getElementsByTagName('character')
                for member in members:
                    if self.name in member.getAttribute('name'):
                        contrib = int(member.getAttribute('contribution'))
                        teamrank= int(member.getAttribute('teamRank')) # 0 if owner; 1 otherwise
                        break
                self.arena[size] = [name, rank, rating, contrib, teamrank]
        if demo:
            for size, data in self.arena.iteritems():
                print 'arena', size, data

        try:    #above this is on every character sheet (including skills, etc.)
            char = sheet.getElementsByTagName('characterTab')[0]
        except IndexError: char = None
        if char:
            spec = char.getElementsByTagName('talentSpec')[0]
            self.talents = (int(spec.getAttribute('treeOne')), int(spec.getAttribute('treeTwo')), int(spec.getAttribute('treeThree')))
            if demo: print 'talents', self.talents

            buffpairs = []
            if char.getElementsByTagName('buffs')[0].hasChildNodes():
                buffs = char.getElementsByTagName('buffs')[0].getElementsByTagName('spell')
                for buff in buffs:
                    buffpairs.append((buff.getAttribute('name'), buff.getAttribute('effect')))
            if char.getElementsByTagName('debuffs')[0].hasChildNodes():
                debuffs = char.getElementsByTagName('debuffs')[0].getElementsByTagName('spell')
                for debuff in debuffs:
                    buffpairs.append((debuff.getAttribute('name'), debuff.getAttribute('effect')))
            if buffpairs:
                self.buffs = dict(buffpairs)
            else: self.buffs = {}
            if demo:
                for buff, effect in self.buffs.iteritems():
                    print buff, effect

            pvp = char.getElementsByTagName('pvp')[0]
            kills = int(pvp.getElementsByTagName('lifetimehonorablekills')[0].getAttribute('value'))
            if kills < 10000: self.kills = kills
            else: self.kills = '%d %03d' % divmod(kills, 1000)
            self.arenacurr = int(pvp.getElementsByTagName('arenacurrency')[0].getAttribute('value'))
            if demo: print 'pvp', self.kills, self.arenacurr

            profpairs = []
            profs = char.getElementsByTagName('professions')[0].getElementsByTagName('skill')
            for prof in profs:
                profpairs.append((prof.getAttribute('name'), int(prof.getAttribute('value'))))
            self.professions = dict(profpairs)
            if demo:
                for prof, value in self.professions.iteritems():
                    print prof, value

            self.titles = []
            knowntitles = char.getElementsByTagName('knownTitles')[0].getElementsByTagName('title')
            for title in knowntitles:
                self.titles.append(title.getAttribute('value') % self.name)
            if demo:
                for title in self.titles:
                    print title

            bars = char.getElementsByTagName('characterBars')[0]
            health = int(bars.getElementsByTagName('health')[0].getAttribute('effective'))
            if health < 10000: self.health = health
            else: self.health = '%d %03d' % divmod(health, 1000)
            secondbar = bars.getElementsByTagName('secondBar')[0]
            if secondbar.getAttribute('type') == 'm':
                mana = int(secondbar.getAttribute('effective'))
                if mana < 8000: self.mana = mana
                else: self.mana = '%2d %03d' % divmod(mana, 1000)
                self.mp5 = int(secondbar.getAttribute('casting'))
            else: self.mana = self.mp5 = 0
            if demo: print 'health, mana', self.health, self.mana, self.mp5

            stat = char.getElementsByTagName('baseStats')[0]
            self.stats = {}
            for x in stats[self.classid]:
                self.stats[x] = int(stat.getElementsByTagName(x)[0].getAttribute('effective'))
            if demo:
                for x, value in self.stats.iteritems():
                    print x, value

            res = char.getElementsByTagName('resistances')[0]
            self.resist = {
                'arcane':   int(res.getElementsByTagName('arcane')[0].getAttribute('value')),
                'fire':     int(res.getElementsByTagName('fire')[0].getAttribute('value')),
                'frost':    int(res.getElementsByTagName('frost')[0].getAttribute('value')),
                'holy':     int(res.getElementsByTagName('holy')[0].getAttribute('value')),
                'nature':   int(res.getElementsByTagName('nature')[0].getAttribute('value')),
                'shadow':   int(res.getElementsByTagName('shadow')[0].getAttribute('value')),
                }
            if demo:
                for school, res in self.resist.iteritems():
                    print 'resist', school, res

            if not 'melee' in combats[self.classid]:
                self.melee = None
            else:
                melee = char.getElementsByTagName('melee')[0]
                MH =    melee.getElementsByTagName('mainHandDamage')[0]
                OH =    melee.getElementsByTagName('offHandDamage')[0]
                power = melee.getElementsByTagName('power')[0]
                hit =   melee.getElementsByTagName('hitRating')[0]
                crit =  melee.getElementsByTagName('critChance')[0]
                expert = melee.getElementsByTagName('expertise')[0]
                self.melee = {
                    'mainhand': [float(MH.getAttribute('dps')), float(MH.getAttribute('speed'))],
                    'offhand':  [float(OH.getAttribute('dps')), float(OH.getAttribute('speed'))],
                    'power':    [float(power.getAttribute('increasedDps')), int(power.getAttribute('effective'))],
                    'hit':      [float(hit.getAttribute('increasedHitPercent')), int(hit.getAttribute('value'))],
                    'crit':     [float(crit.getAttribute('percent')), int(crit.getAttribute('rating'))],
                    'expert':   [float(expert.getAttribute('percent')), int(expert.getAttribute('value'))],
                    }
                if demo:
                    for stat, values in self.melee.iteritems():
                        print 'melee', stat, values

            #ranged
            if not 'ranged' in combats[self.classid]:
                self.ranged = None
            else:
                ranged = char.getElementsByTagName('ranged')[0]
                damage = ranged.getElementsByTagName('damage')[0]
                power = ranged.getElementsByTagName('power')[0]
                hit =   ranged.getElementsByTagName('hitRating')[0]
                crit =  ranged.getElementsByTagName('critChance')[0]
                self.ranged = {
                    'damage':   [float(damage.getAttribute('dps')), float(damage.getAttribute('speed'))],
                    'power':    [float(power.getAttribute('increasedDps')), int(power.getAttribute('effective'))],
                    'hit':      [float(hit.getAttribute('increasedHitPercent')), int(hit.getAttribute('value'))],
                    'crit':     [float(crit.getAttribute('percent')), int(crit.getAttribute('rating'))],
                    }
                if demo:
                    for stat, values in self.ranged.iteritems():
                        print 'ranged', stat, values

            #spell
            if not 'spell' in combats[self.classid]: self.spell = None; self.heal = 0; self.pen = 0
            else:
                for tag in char.getElementsByTagName('spell'):
                    if tag.getElementsByTagName('bonusDamage'):
                        spell = tag
                        break
                bonus = spell.getElementsByTagName('bonusDamage')[0]
                self.heal = int(spell.getElementsByTagName('bonusHealing')[0].getAttribute('value'))
                hit =   spell.getElementsByTagName('hitRating')[0]
                crit =  spell.getElementsByTagName('critChance')[0]
                self.pen = int(spell.getElementsByTagName('penetration')[0].getAttribute('value'))
                self.spell = {}
                for school in schools[self.classid]:
                    self.spell[school] = int(bonus.getElementsByTagName(school)[0].getAttribute('value')), float(crit.getElementsByTagName(school)[0].getAttribute('percent'))
                if demo:
                    for school, values in self.spell.iteritems():
                        print 'damage', school, values
                    print 'heal, pen', self.heal, self.pen

            #defenses
            if not 'defenses' in combats[self.classid]: self.defenses = None
            else:
                defs =  char.getElementsByTagName('defenses')[0]
                armor = defs.getElementsByTagName('armor')[0]
                defense = defs.getElementsByTagName('defense')[0]
                dodge = defs.getElementsByTagName('dodge')[0]
                parry = defs.getElementsByTagName('parry')[0]
                block = defs.getElementsByTagName('block')[0]
                res = defs.getElementsByTagName('resilience')[0]
                self.defenses = {
                    'armor':    [float(armor.getAttribute('percent')), int(armor.getAttribute('effective'))],
                    'defense':  [float(defense.getAttribute('value')) + int(defense.getAttribute('plusDefense')), int(defense.getAttribute('rating'))],
                    'dodge':    [float(dodge.getAttribute('percent')), int(dodge.getAttribute('rating'))],
                    'parry':    [float(parry.getAttribute('percent')), int(parry.getAttribute('rating'))],
                    'block':    [float(block.getAttribute('percent')), int(block.getAttribute('rating'))],
                    'resilience': [float(res.getAttribute('damagePercent')), float(res.getAttribute('hitPercent')), float(res.getAttribute('value'))],
                    }
                self.defenses['pd'] = self.defenses['dodge'][0] + self.defenses['parry'][0]
                self.defenses['pdb'] = self.defenses['pd'] + self.defenses['block'][0]
                if demo:
                    for attribute, values in self.defenses.iteritems():
                        print attribute, values

            items = char.getElementsByTagName('items')[0].getElementsByTagName('item')
            self.item = {}
            for item in items:
                slot = int(item.getAttribute('slot'))
                itemid = int(item.getAttribute('id'))
                random = int(item.getAttribute('randomPropertiesId'))
                enchant = int(item.getAttribute('permanentenchant'))
                gems = int(item.getAttribute('gem0Id')), int(item.getAttribute('gem1Id')), int(item.getAttribute('gem2Id'))
                self.item[slot] = [itemid, random, enchant, gems]
            for i in range(-1, 19):
                try: self.item[i]
                except KeyError: self.item[i] = ''
            self.slot = {
                'head':     self.item[0],
                'neck':     self.item[1],
                'shoulder': self.item[2],
                'shirt':    self.item[3],
                'chest':    self.item[4],
                'waist':    self.item[5],
                'legs':     self.item[6],
                'feet':     self.item[7],
                'wrist':    self.item[8],
                'hands':    self.item[9],
                'ring1':    self.item[10],
                'ring2':    self.item[11],
                'trink1':   self.item[12],
                'trink2':   self.item[13],
                'back':     self.item[14],
                'main':     self.item[15],
                'off':      self.item[16],
                'ranged':   self.item[17],
                'tabard':   self.item[18],
                'arrow':    self.item[-1],
                }
            if demo:
                print 'items'
                for slot, item in self.slot.iteritems():
                    print slot, item

if __name__ == "__main__":
    whoshe()
